Passed
Pull Request — master (#187)
by Alejandro
09:37
created

.loadVisits   A

Complexity

Conditions 1

Size

Total Lines 9
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 9
ccs 7
cts 7
cp 1
rs 10
c 0
b 0
f 0
cc 1
crap 1
1
import { faCircleNotch as preloader } from '@fortawesome/free-solid-svg-icons';
2
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
import { isEmpty, mapObjIndexed, values } from 'ramda';
4
import React from 'react';
5
import { Card } from 'reactstrap';
6
import PropTypes from 'prop-types';
7
import DateRangeRow from '../utils/DateRangeRow';
8
import MutedMessage from '../utils/MuttedMessage';
9
import { formatDate } from '../utils/utils';
10
import SortableBarGraph from './SortableBarGraph';
11
import { shortUrlVisitsType } from './reducers/shortUrlVisits';
12
import VisitsHeader from './VisitsHeader';
13
import GraphCard from './GraphCard';
14
import { shortUrlDetailType } from './reducers/shortUrlDetail';
15
16 1
const ShortUrlVisits = (
17
  { processStatsFromVisits },
18
  OpenMapModalBtn
19 7
) => class ShortUrlVisits extends React.PureComponent {
20 7
  static propTypes = {
21
    match: PropTypes.shape({
22
      params: PropTypes.object,
23
    }),
24
    getShortUrlVisits: PropTypes.func,
25
    shortUrlVisits: shortUrlVisitsType,
26
    getShortUrlDetail: PropTypes.func,
27
    shortUrlDetail: shortUrlDetailType,
28
    cancelGetShortUrlVisits: PropTypes.func,
29
  };
30
31 7
  state = { startDate: undefined, endDate: undefined };
32 7
  loadVisits = () => {
33 10
    const { match: { params }, getShortUrlVisits } = this.props;
34 10
    const { shortCode } = params;
35 10
    const dates = mapObjIndexed(formatDate(), this.state);
36 10
    const { startDate, endDate } = dates;
37
38
    // While the "page" is loaded, use the timestamp + filtering dates as memoization IDs for stats calcs
39 10
    this.memoizationId = `${this.timeWhenMounted}_${shortCode}_${startDate}_${endDate}`;
40 10
    getShortUrlVisits(shortCode, dates);
41
  };
42
43
  componentDidMount() {
44 7
    const { match: { params }, getShortUrlDetail } = this.props;
45 7
    const { shortCode } = params;
46
47 7
    this.timeWhenMounted = new Date().getTime();
48 7
    this.loadVisits();
49 7
    getShortUrlDetail(shortCode);
50
  }
51
52
  componentWillUnmount() {
53 7
    this.props.cancelGetShortUrlVisits();
54
  }
55
56
  render() {
57 10
    const { shortUrlVisits, shortUrlDetail } = this.props;
58
59 10
    const renderVisitsContent = () => {
60 10
      const { visits, loading, loadingLarge, error } = shortUrlVisits;
61
62 10
      if (loading) {
63 2
        const message = loadingLarge ? 'This is going to take a while... :S' : 'Loading...';
64
65 2
        return <MutedMessage><FontAwesomeIcon icon={preloader} spin /> {message}</MutedMessage>;
66
      }
67
68 8
      if (error) {
69 1
        return (
70
          <Card className="mt-4" body inverse color="danger">
71
            An error occurred while loading visits :(
72
          </Card>
73
        );
74
      }
75
76 7
      if (isEmpty(visits)) {
77 1
        return <MutedMessage>There are no visits matching current filter  :(</MutedMessage>;
78
      }
79
80 6
      const { os, browsers, referrers, countries, cities, citiesForMap } = processStatsFromVisits(
81
        { id: this.memoizationId, visits }
82
      );
83 6
      const mapLocations = values(citiesForMap);
84
85 6
      return (
86
        <div className="row">
87
          <div className="col-xl-4 col-lg-6">
88
            <GraphCard title="Operating systems" stats={os} />
89
          </div>
90
          <div className="col-xl-4 col-lg-6">
91
            <GraphCard title="Browsers" stats={browsers} />
92
          </div>
93
          <div className="col-xl-4">
94
            <SortableBarGraph
95
              stats={referrers}
96
              withPagination={false}
97
              title="Referrers"
98
              sortingItems={{
99
                name: 'Referrer name',
100
                amount: 'Visits amount',
101
              }}
102
            />
103
          </div>
104
          <div className="col-lg-6">
105
            <SortableBarGraph
106
              stats={countries}
107
              title="Countries"
108
              sortingItems={{
109
                name: 'Country name',
110
                amount: 'Visits amount',
111
              }}
112
            />
113
          </div>
114
          <div className="col-lg-6">
115
            <SortableBarGraph
116
              stats={cities}
117
              title="Cities"
118
              extraHeaderContent={(activeCities) =>
119 2
                mapLocations.length > 0 &&
120
                  <OpenMapModalBtn modalTitle="Cities" locations={mapLocations} activeCities={activeCities} />
121
              }
122
              sortingItems={{
123
                name: 'City name',
124
                amount: 'Visits amount',
125
              }}
126
            />
127
          </div>
128
        </div>
129
      );
130
    };
131 20
    const setDate = (dateField) => (date) => this.setState({ [dateField]: date }, this.loadVisits);
132
133 10
    return (
134
      <div className="shlink-container">
135
        <VisitsHeader shortUrlDetail={shortUrlDetail} />
136
137
        <section className="mt-4">
138
          <DateRangeRow
139
            startDate={this.state.startDate}
140
            endDate={this.state.endDate}
141
            onStartDateChange={setDate('startDate')}
142
            onEndDateChange={setDate('endDate')}
143
          />
144
        </section>
145
146
        <section>
147
          {renderVisitsContent()}
148
        </section>
149
      </div>
150
    );
151
  }
152
};
153
154
export default ShortUrlVisits;
155